Imports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports C4F.DevKit.Calendar.Parser
Imports System.IO

Namespace C4F.DevKit.Calendar
	''' <summary>
	''' A class which represents a calendar appointment.
	''' </summary>
	Public Class Appointment
		#Region "Private Members"

		Private _UID As Guid

		Private _occurrences As List(Of Appointment)

		Private _sequenceNumber As Integer

		Private _isPartOfSeries As Boolean

		Private _extraProperties As List(Of String)

		Private _summary As String

		Private _location As String

		Private _url As String

		Private _startDateTime As DateTime

		Private _endDateTime As DateTime

		Private _isAllDayEvent As Boolean

		Private _occurrence As DateTime

		Private _timestamp As DateTime

		Private _attendees As List(Of Attendee)

		Private _reminder As Reminder

		Private _recurrenceRule As RecurrenceRule

		Private _notes As String

		#End Region

		#Region "Internal Methods"

		Friend Sub SetUID(ByVal uid As Guid)
			_UID = uid
		End Sub

		#End Region

		#Region "Public Constructors"

		''' <summary>
		''' Creates a new appointment.
		''' </summary>
		Public Sub New()
			Attendees = New List(Of Attendee)()
			SetUID(Guid.NewGuid())
			Timestamp = DateTime.Now
			Occurrences = New List(Of Appointment)()
			ExtraProperties = New List(Of String)()
		End Sub

		#End Region

		#Region "Internal Properties"

		Friend Property Occurrences() As List(Of Appointment)
			Get
				Return _occurrences
			End Get
			Set(ByVal value As List(Of Appointment))
				_occurrences = value
			End Set
		End Property

		Friend Property SequenceNumber() As Integer
			Get
				Return _sequenceNumber
			End Get
			Set(ByVal value As Integer)
				_sequenceNumber = value
			End Set
		End Property

		Friend Property IsPartOfSeries() As Boolean
			Get
				Return _isPartOfSeries
			End Get
			Set(ByVal value As Boolean)
				_isPartOfSeries = value
			End Set
		End Property

		Friend Property ExtraProperties() As List(Of String)
			Get
				Return _extraProperties
			End Get
			Set(ByVal value As List(Of String))
				_extraProperties = value
			End Set
		End Property

		#End Region

		#Region "Public Properties"

		''' <summary>
		''' A summary of the appointment.
		''' </summary>
		Public Property Summary() As String
			Get
				Return _summary
			End Get
			Set(ByVal value As String)
				_summary = value
			End Set
		End Property

		''' <summary>
		''' The location of the appointment.
		''' </summary>
		Public Property Location() As String
			Get
				Return _location
			End Get
			Set(ByVal value As String)
				_location = value
			End Set
		End Property

		''' <summary>
		''' The unique identifier for the appointment.
		''' </summary>
		Public ReadOnly Property UID() As Guid
			Get
				Return _UID
			End Get
		End Property

		''' <summary>
		''' The URL of the appointment.
		''' </summary>
		Public Property URL() As String
			Get
				Return _url
			End Get
			Set(ByVal value As String)
				_url = value
			End Set
		End Property

		''' <summary>
		''' The starting date and time of the appointment.
		''' </summary>
		Public Property StartDateTime() As DateTime
			Get
				Return _startDateTime
			End Get
			Set(ByVal value As DateTime)
				_startDateTime = value
			End Set
		End Property

		''' <summary>
		''' The ending date and time of the appointment.
		''' </summary>
		Public Property EndDateTime() As DateTime
			Get
				Return _endDateTime
			End Get
			Set(ByVal value As DateTime)
				_endDateTime = value
			End Set
		End Property

		''' <summary>
		''' The start date and time of the appointment, in the time
		''' zone of the current system.
		''' </summary>
		Public ReadOnly Property LocalStartDateTime() As DateTime
			Get
				Return TimeZone.CurrentTimeZone.ToLocalTime(_startDateTime)
			End Get
		End Property

		''' <summary>
		''' The end date and time of the appointment, in the time
		''' zone of the current system.
		''' </summary>
		Public ReadOnly Property LocalEndDateTime() As DateTime
			Get
				Return TimeZone.CurrentTimeZone.ToLocalTime(_endDateTime)
			End Get
		End Property

		''' <summary>
		''' Whether or not this appointment is an all-day event.
		''' </summary>
		Public Property IsAllDayEvent() As Boolean
			Get
				Return _isAllDayEvent
			End Get
			Set(ByVal value As Boolean)
				_isAllDayEvent = value
			End Set
		End Property

		''' <summary>
		''' The specific occurence of this appointment, out of a series of appointments.
		''' </summary>
		Public Property Occurrence() As DateTime
			Get
				Return _occurrence
			End Get
			Set(ByVal value As DateTime)
				_occurrence = value
			End Set
		End Property

		''' <summary>
		''' The creation date and time of the appointment.
		''' </summary>
		Public Property Timestamp() As DateTime
			Get
				Return _timestamp
			End Get
			Set(ByVal value As DateTime)
				_timestamp = value
			End Set
		End Property

		''' <summary>
		''' The list of attendees for the appointment.
		''' </summary>
		Public Property Attendees() As List(Of Attendee)
			Get
				Return _attendees
			End Get
			Set(ByVal value As List(Of Attendee))
				_attendees = value
			End Set
		End Property

		''' <summary>
		''' The reminder for the event.
		''' </summary>
		Public Property Reminder() As Reminder
			Get
				Return _reminder
			End Get
			Set(ByVal value As Reminder)
				_reminder = value
			End Set
		End Property

		''' <summary>
		''' The rule which specifies how the appointment repeats, if it does at all.
		''' </summary>
		Public Property RecurrenceRule() As RecurrenceRule
			Get
				Return _recurrenceRule
			End Get
			Set(ByVal value As RecurrenceRule)
				_recurrenceRule = value
			End Set
		End Property

		''' <summary>
		''' General notes about the appointment.
		''' </summary>
		Public Property Notes() As String
			Get
				Return _notes
			End Get
			Set(ByVal value As String)
				_notes = value
			End Set
		End Property

		''' <summary>
		''' Gets and sets whether or not this event recurs on Sundays.
		''' </summary>
		Public Property RecurOnSunday() As Boolean
			Get
				Return DoesRecurOnDay(Weekday.Sunday)
			End Get
			Set(ByVal value As Boolean)
				RecurOnDay(Weekday.Sunday)
			End Set
		End Property

		''' <summary>
		''' Gets and sets whether or not this event recurs on Mondays.
		''' </summary>
		Public Property RecurOnMonday() As Boolean
			Get
				Return DoesRecurOnDay(Weekday.Monday)
			End Get
			Set(ByVal value As Boolean)
				RecurOnDay(Weekday.Monday)
			End Set
		End Property

		''' <summary>
		''' Gets and sets whether or not this event recurs on Tuesdays.
		''' </summary>
		Public Property RecurOnTuesday() As Boolean
			Get
				Return DoesRecurOnDay(Weekday.Tuesday)
			End Get
			Set(ByVal value As Boolean)
				RecurOnDay(Weekday.Tuesday)
			End Set
		End Property

		''' <summary>
		''' Gets and sets whether or not this event recurs on Wednesdays.
		''' </summary>
		Public Property RecurOnWednesday() As Boolean
			Get
				Return DoesRecurOnDay(Weekday.Wednesday)
			End Get
			Set(ByVal value As Boolean)
				RecurOnDay(Weekday.Wednesday)
			End Set
		End Property

		''' <summary>
		''' Gets and sets whether or not this event recurs on Thursdays.
		''' </summary>
		Public Property RecurOnThursday() As Boolean
			Get
				Return DoesRecurOnDay(Weekday.Thursday)
			End Get
			Set(ByVal value As Boolean)
				RecurOnDay(Weekday.Thursday)
			End Set
		End Property

		''' <summary>
		''' Gets and sets whether or not this event recurs on Fridays.
		''' </summary>
		Public Property RecurOnFriday() As Boolean
			Get
				Return DoesRecurOnDay(Weekday.Friday)
			End Get
			Set(ByVal value As Boolean)
				RecurOnDay(Weekday.Friday)
			End Set
		End Property

		''' <summary>
		''' Gets and sets whether or not this event recurs on Saturdays.
		''' </summary>
		Public Property RecurOnSaturday() As Boolean
			Get
				Return DoesRecurOnDay(Weekday.Saturday)
			End Get
			Set(ByVal value As Boolean)
				RecurOnDay(Weekday.Saturday)
			End Set
		End Property

		#End Region

		#Region "Public Methods"

		''' <summary>
		''' Validates that the appointment has all required fields (Summary, StartDateTime, EndDateTime).
		''' Also validates that the end of the appointment is either at the same time or later than
		''' the start.
		''' </summary>
		''' <returns>True if the appointment is valid, false otherwise.</returns>
		Public Function Validate() As Boolean
			Return (StartDateTime <> New DateTime()) AndAlso (EndDateTime <> New DateTime()) AndAlso StartDateTime <= EndDateTime AndAlso ((Not String.IsNullOrEmpty(Summary)))
		End Function

		''' <summary>
		''' Saves the appointment to a calendar file, adding it to the end.
		''' </summary>
		''' <param name="filePath">The file path of the calendar to add the appointment to.</param>
		Public Sub Save(ByVal filePath As String)
			Using file As FileStream = New FileStream(filePath, FileMode.Open)
				Save(file)
			End Using
		End Sub

		''' <summary>
		''' Saves the appointment to a calendar file, adding it to the end.
		''' </summary>
		''' <param name="file">The file stream of the calendar to save the appointment to.</param>
		Public Sub Save(ByVal file As FileStream)
			Dim writer As Writer = New Writer(file)
			writer.AddToCalendar(Me)
			writer.Close()
		End Sub

		''' <summary>
		''' Adds a certain weekday on which to recur. This method should
		''' only be used when the recurrence rule is set to use a weekly
		''' recurrence.
		''' </summary>
		''' <param name="weekday">The weekday on which to recur.</param>
		Public Sub RecurOnDay(ByVal weekday As Weekday)

			If DoesRecurOnDay(weekday) Then
				Return
			End If

			Me.RecurrenceRule.MonthWeekdays.Add(New MonthWeekday(weekday, 0))
		End Sub

		''' <summary>
		''' Tells whether this appointment recurs on a certain weekday.
		''' This method should only be used on appointments with weekly
		''' recurrence rules.
		''' </summary>
		''' <param name="weekday">The weekday to check for recurrence.</param>
		''' <returns>Whether or not the appointment recurs on the given day.</returns>
		Public Function DoesRecurOnDay(ByVal weekday As Weekday) As Boolean
			For Each mw As MonthWeekday In Me.RecurrenceRule.MonthWeekdays
				If mw.Weekday = weekday AndAlso mw.WeekNumber = 0 Then
					Return True
				End If
			Next mw

			Return False
		End Function

		''' <summary>
		''' Sets this appointment to recur every day.
		''' </summary>
		Public Sub SetDailyRecurrence()
			RecurrenceRule = New RecurrenceRule(Frequency.Daily)
		End Sub

		''' <summary>
		''' Sets this apppointment to recur every day.
		''' </summary>
		''' <param name="count">The number of times for the appointment to recur.</param>
		Public Sub SetDailyRecurrence(ByVal count As Integer)
			SetRecurrence(Frequency.Daily, count)
		End Sub

		''' <summary>
		''' Sets this appointment to recur every day.
		''' </summary>
		''' <param name="end">The date on which to end the recurrence.</param>
		Public Sub SetDailyRecurrence(ByVal [end] As DateTime)
			SetRecurrence(Frequency.Daily, [end])
		End Sub

		''' <summary>
		''' Sets this appointment to recur once every week, on the day of
		''' the week on which it starts.
		''' </summary>
		Public Sub SetWeeklyRecurrence()
			Dim weekdays As List(Of Weekday) = New List(Of Weekday)()
			weekdays.Add(CType(CInt(Fix(StartDateTime.DayOfWeek)), Weekday))
			SetWeeklyRecurrence(weekdays)
		End Sub

		''' <summary>
		''' Sets this appointment to recur once every week.
		''' </summary>
		''' <param name="count">The number of times for the appointment to recur.</param>
		Public Sub SetWeeklyRecurrence(ByVal count As Integer)
			SetRecurrence(Frequency.Weekly, count)
		End Sub

		''' <summary>
		''' Sets this appointment to recur once every week.
		''' </summary>
		''' <param name="end">The date on which to end the recurrence.</param>
		Public Sub SetWeeklyRecurrence(ByVal [end] As DateTime)
			SetRecurrence(Frequency.Weekly, [end])
		End Sub

		''' <summary>
		''' Sets this appointment to recur weekly.
		''' </summary>
		''' <param name="weekdays">The days of the week on which to recur.</param>
		Public Sub SetWeeklyRecurrence(ByVal weekdays As List(Of Weekday))
			RecurrenceRule = New RecurrenceRule(Frequency.Weekly)

			For Each weekday As Weekday In weekdays
				RecurrenceRule.MonthWeekdays.Add(New MonthWeekday(weekday, 0))
			Next weekday
		End Sub

		''' <summary>
		''' Sets this appointment to recur weekly.
		''' </summary>
		''' <param name="weekdays">The days of the week on which to recur.</param>
		''' <param name="count">The number of times for the appointment to recur.</param>
		Public Sub SetWeeklyRecurrence(ByVal weekdays As List(Of Weekday), ByVal count As Integer)
			SetRecurrence(Frequency.Weekly, count)
		End Sub

		''' <summary>
		''' Sets this appointment to recur weekly.
		''' </summary>
		''' <param name="weekdays">The days of the week on which to recur.</param>
		''' <param name="end">The date on which to end the recurrence.</param>
		Public Sub SetWeeklyRecurrence(ByVal weekdays As List(Of Weekday), ByVal [end] As DateTime)
			SetRecurrence(Frequency.Weekly, [end])
		End Sub

		''' <summary>
		''' Sets this appointment to recur once a month, on the day of the month
		''' on which this appointment starts.
		''' </summary>
		Public Sub SetMonthlyRecurrence()
			RecurrenceRule = New RecurrenceRule(Frequency.Monthly)
		End Sub

		''' <summary>
		''' Sets this appointment to recur once a month, on the day of the month
		''' on which this appointment starts.
		''' </summary>
		''' <param name="count">The number of times for the appointment to recur.</param>
		Public Sub SetMonthlyRecurrence(ByVal count As Integer)
			SetRecurrence(Frequency.Monthly, count)
		End Sub

		''' <summary>
		''' Sets this appointment to recur once a month, on the day of the month
		''' on which this appointment starts.
		''' </summary>
		''' <param name="end">The date on which to end the recurrence.</param>
		Public Sub SetMonthlyRecurrence(ByVal [end] As DateTime)
			SetRecurrence(Frequency.Monthly, [end])
		End Sub

		''' <summary>
		''' Sets this appointment to recur once a year, on the date on which the
		''' appointment starts.
		''' </summary>
		Public Sub SetYearlyRecurrence()
			RecurrenceRule = New RecurrenceRule(Frequency.Yearly)
		End Sub

		''' <summary>
		''' Sets this appointment to recur once a year, on the date on which the
		''' appointment starts.
		''' </summary>
		''' <param name="count">The number of times for the appointment to recur.</param>
		Public Sub SetYearlyRecurrence(ByVal count As Integer)
			SetRecurrence(Frequency.Yearly, count)
		End Sub

		''' <summary>
		''' Sets this appointment to recur once a year, on the date on which the
		''' appointment starts.
		''' </summary>
		''' <param name="end">The date on which to end the recurrence.</param>
		Public Sub SetYearlyRecurrence(ByVal [end] As DateTime)
			SetRecurrence(Frequency.Monthly, [end])
		End Sub

		''' <summary>
		''' Sets a recurrence rule for this appointment.
		''' </summary>
		''' <param name="freq">The frequency type of this recurrence.</param>
		''' <param name="count">The number of times for the appointment to recur.</param>
		Public Sub SetRecurrence(ByVal freq As Frequency, ByVal count As Integer)
			RecurrenceRule = New RecurrenceRule(freq)
			RecurrenceRule.Count = count
		End Sub

		''' <summary>
		''' Sets a recurrence rule for this appointment.
		''' </summary>
		''' <param name="freq">The frequency type of this recurrence.</param>
		''' <param name="end">The date on which to end the recurrence.</param>
		Public Sub SetRecurrence(ByVal freq As Frequency, ByVal [end] As DateTime)
			RecurrenceRule = New RecurrenceRule(freq)
			RecurrenceRule.EndDateTime = [end]
		End Sub

		#End Region
	End Class
End Namespace
